/**
 * Created by scenic on 2017/6/10.
 */
;(function($) {

    // TODO rewrite as a widget, removing all the extra plugins
    $.extend($.fn, {
        swapClass: function(c1, c2) {
            var c1Elements = this.filter('.' + c1);
            this.filter('.' + c2).removeClass(c2).addClass(c1);
            c1Elements.removeClass(c1).addClass(c2);
            return this;
        },
        replaceClass: function(c1, c2) {
            return this.filter('.' + c1).removeClass(c1).addClass(c2).end();
        },
        hoverClass: function(className) {
            className = className || "hover";
            return this.hover(function() {
                $(this).addClass(className);
            }, function() {
                $(this).removeClass(className);
            });
        },
        heightToggle: function(animated, callback) {
            animated ?
                this.animate({ height: "toggle" }, animated, callback) :
                this.each(function(){
                    jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
                    if(callback)
                        callback.apply(this, arguments);
                });
        },
        heightHide: function(animated, callback) {
            if (animated) {
                this.animate({ height: "hide" }, animated, callback);
            } else {
                this.hide();
                if (callback)
                    this.each(callback);
            }
        },
        prepareBranches: function(settings) {
            if (!settings.prerendered) {
                // mark last tree items
                this.filter(":last-child:not(ul)").addClass(CLASSES.last);
                // collapse whole tree, or only those marked as closed, anyway except those marked as open
                this.filter((settings.collapsed ? "" : "." + CLASSES.closed) + ":not(." + CLASSES.open + ")").find(">ul").hide();
            }
            // return all items with sublists
            return this.filter(":has(>ul)");
        },
        applyClasses: function(settings, toggler) {
            // TODO use event delegation
            this.filter(":has(>ul):not(:has(>a))").find(">span").unbind("click.treeview").bind("click.treeview", function(event) {
                // don't handle click events on children, eg. checkboxes
                if ( this == event.target )
                    toggler.apply($(this).next());
            }).add( $("a", this) ).hoverClass();

            if (!settings.prerendered) {
                // handle closed ones first
                this.filter(":has(>ul:hidden)")
                    .addClass(CLASSES.expandable)
                    .replaceClass(CLASSES.last, CLASSES.lastExpandable);

                // handle open ones
                this.not(":has(>ul:hidden)")
                    .addClass(CLASSES.collapsable)
                    .replaceClass(CLASSES.last, CLASSES.lastCollapsable);

                // create hitarea if not present
                var hitarea = this.find("div." + CLASSES.hitarea);
                if (!hitarea.length)
                    hitarea = this.prepend("<div class=\"" + CLASSES.hitarea + "\"/>").find("div." + CLASSES.hitarea);
                hitarea.removeClass().addClass(CLASSES.hitarea).each(function() {
                    var classes = "";
                    $.each($(this).parent().attr("class").split(" "), function() {
                        classes += this + "-hitarea ";
                    });
                    $(this).addClass( classes );
                })
            }

            // apply event to hitarea
            this.find("div." + CLASSES.hitarea).click( toggler );
        },
        treeview: function(settings) {

            settings = $.extend({
                cookieId: "treeview"
            }, settings);

            if ( settings.toggle ) {
                var callback = settings.toggle;
                settings.toggle = function() {
                    return callback.apply($(this).parent()[0], arguments);
                };
            }

            // factory for treecontroller
            function treeController(tree, control) {
                // factory for click handlers
                function handler(filter) {
                    return function() {
                        // reuse toggle event handler, applying the elements to toggle
                        // start searching for all hitareas
                        toggler.apply( $("div." + CLASSES.hitarea, tree).filter(function() {
                            // for plain toggle, no filter is provided, otherwise we need to check the parent element
                            return filter ? $(this).parent("." + filter).length : true;
                        }) );
                        return false;
                    };
                }
                // click on first element to collapse tree
                $("a:eq(0)", control).click( handler(CLASSES.collapsable) );
                // click on second to expand tree
                $("a:eq(1)", control).click( handler(CLASSES.expandable) );
                // click on third to toggle tree
                $("a:eq(2)", control).click( handler() );
            }

            // handle toggle event
            function toggler() {
                $(this)
                    .parent()
                    // swap classes for hitarea
                    .find(">.hitarea")
                    .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
                    .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
                    .end()
                    // swap classes for parent li
                    .swapClass( CLASSES.collapsable, CLASSES.expandable )
                    .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
                    // find child lists
                    .find( ">ul" )
                    // toggle them
                    .heightToggle( settings.animated, settings.toggle );
                if ( settings.unique ) {
                    $(this).parent()
                        .siblings()
                        // swap classes for hitarea
                        .find(">.hitarea")
                        .replaceClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
                        .replaceClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea )
                        .end()
                        .replaceClass( CLASSES.collapsable, CLASSES.expandable )
                        .replaceClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
                        .find( ">ul" )
                        .heightHide( settings.animated, settings.toggle );
                }
            }
            this.data("toggler", toggler);

            function serialize() {
                function binary(arg) {
                    return arg ? 1 : 0;
                }
                var data = [];
                branches.each(function(i, e) {
                    data[i] = $(e).is(":has(>ul:visible)") ? 1 : 0;
                });
                $.cookie(settings.cookieId, data.join(""), settings.cookieOptions );
            }

            function deserialize() {
                var stored = $.cookie(settings.cookieId);
                if ( stored ) {
                    var data = stored.split("");
                    branches.each(function(i, e) {
                        $(e).find(">ul")[ parseInt(data[i]) ? "show" : "hide" ]();
                    });
                }
            }

            // add treeview class to activate styles
            this.addClass("treeview");

            // prepare branches and find all tree items with child lists
            var branches = this.find("li").prepareBranches(settings);

            switch(settings.persist) {
                case "cookie":
                    var toggleCallback = settings.toggle;
                    settings.toggle = function() {
                        serialize();
                        if (toggleCallback) {
                            toggleCallback.apply(this, arguments);
                        }
                    };
                    deserialize();
                    break;
                case "location":
                    var current = this.find("a").filter(function() {
                        return location.href.toLowerCase().indexOf(this.href.toLowerCase()) == 0;
                    });
                    if ( current.length ) {
                        // TODO update the open/closed classes
                        var items = current.addClass("selected").parents("ul, li").add( current.next() ).show();
                        if (settings.prerendered) {
                            // if prerendered is on, replicate the basic class swapping
                            items.filter("li")
                                .swapClass( CLASSES.collapsable, CLASSES.expandable )
                                .swapClass( CLASSES.lastCollapsable, CLASSES.lastExpandable )
                                .find(">.hitarea")
                                .swapClass( CLASSES.collapsableHitarea, CLASSES.expandableHitarea )
                                .swapClass( CLASSES.lastCollapsableHitarea, CLASSES.lastExpandableHitarea );
                        }
                    }
                    break;
            }

            branches.applyClasses(settings, toggler);

            // if control option is set, create the treecontroller and show it
            if ( settings.control ) {
                treeController(this, settings.control);
                $(settings.control).show();
            }

            return this;
        }
    });

    // classes used by the plugin
    // need to be styled via external stylesheet, see first example
    $.treeview = {};
    var CLASSES = ($.treeview.classes = {
        open: "open",
        closed: "closed",
        expandable: "expandable",
        expandableHitarea: "expandable-hitarea",
        lastExpandableHitarea: "lastExpandable-hitarea",
        collapsable: "collapsable",
        collapsableHitarea: "collapsable-hitarea",
        lastCollapsableHitarea: "lastCollapsable-hitarea",
        lastCollapsable: "lastCollapsable",
        lastExpandable: "lastExpandable",
        last: "last",
        hitarea: "hitarea"
    });

})(jQuery)


/**
 * Create a cookie with the given name and value and other optional parameters.
 *
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Set the value of a cookie.
 * @example $.cookie('the_cookie', 'the_value', {expires: 7, path: '/', domain: 'jquery.com', secure: true});
 * @desc Create a cookie with all available options.
 * @example $.cookie('the_cookie', 'the_value');
 * @desc Create a session cookie.
 * @example $.cookie('the_cookie', null);
 * @desc Delete a cookie by passing null as value.
 *
 * @param String name The name of the cookie.
 * @param String value The value of the cookie.
 * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
 * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
 *                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
 *                             If set to null or omitted, the cookie will be a session cookie and will not be retained
 *                             when the the browser exits.
 * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
 * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
 * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
 *                        require a secure protocol (like HTTPS).
 * @type undefined
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
/**
 * Get the value of a cookie with the given name.
 *
 * @example $.cookie('the_cookie');
 * @desc Get the value of a cookie.
 *
 * @param String name The name of the cookie.
 * @return The value of the cookie.
 * @type String
 *
 * @name $.cookie
 * @cat Plugins/Cookie
 * @author Klaus Hartl/klaus.hartl@stilbuero.de
 */
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        var path = options.path ? '; path=' + options.path : '';
        var domain = options.domain ? '; domain=' + options.domain : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};


//sortable
;(function($) {

    if (window.Node && Node.prototype && !Node.prototype.contains) {
        Node.prototype.contains = function (arg) {
            return !!(this.compareDocumentPosition(arg) & 16);
        };
    }


    $.widget("ui.sortableTree", $.extend($.ui.mouse, {
        init: function() {

            //Initialize needed constants
            var self = this, o = this.options;
            this.containerCache = {};
            this.element.addClass("ui-sortableTree");

            //Get the items
            this.refresh();

            //Let's determine the parent's offset
            if(!(/(relative|absolute|fixed)/).test(this.element.css('position'))) this.element.css('position', 'relative');
            this.offset = this.element.offset();

            //Initialize mouse events for interaction
            this.mouseInit();

            //Prepare cursorAt
            if(o.cursorAt && o.cursorAt.constructor == Array)
                o.cursorAt = { left: o.cursorAt[0], top: o.cursorAt[1] };

        },
        plugins: {},
        ui: function(inst) {
            return {
                helper: (inst || this)["helper"],
                position: (inst || this)["position"].current,
                absolutePosition: (inst || this)["position"].absolute,
                instance: this,
                options: this.options,
                element: this.element,
                item: (inst || this)["currentItem"],
                sender: inst ? inst.element : null
            };
        },
        propagate: function(n,e,inst) {
            $.ui.plugin.call(this, n, [e, this.ui(inst)]);
            this.element.triggerHandler(n == "sort" ? n : "sort"+n, [e, this.ui(inst)], this.options[n]);
        },
        serialize: function(o) {

            var items = $(this.options.items, this.element).not('.ui-sortableTree-helper'); //Only the items of the sortable itself
            var str = []; o = o || {};

            items.each(function() {
                var res = ($(this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
                if(res) str.push((o.key || res[1])+'[]='+(o.key ? res[1] : res[2]));
            });

            return str.join('&');

        },
        toArray: function(attr) {
            var items = $(this.options.items, this.element).not('.ui-sortableTree-helper'); //Only the items of the sortable itself
            var ret = [];

            items.each(function() { ret.push($(this).attr(attr || 'id')); });
            return ret;
        },
        enable: function() {
            this.element.removeClass("ui-sortableTree-disabled");
            this.options.disabled = false;
        },
        disable: function() {
            this.element.addClass("ui-sortableTree-disabled");
            this.options.disabled = true;
        },
        /* Be careful with the following core functions */
        intersectsWith: function(item) {

            var x1 = this.position.absolute.left - 10, x2 = x1 + 10,
                y1 = this.position.absolute.top - 10, y2 = y1 + 10;
            var l = item.left, r = l + item.width,
                t = item.top,  b = t + item.height;

            return (   l < x1 + (this.helperProportions.width  / 2)    // Right Half
            &&     x2 - (this.helperProportions.width  / 2) < r    // Left Half
            && t < y1 + (this.helperProportions.height / 2)        // Bottom Half
            &&     y2 - (this.helperProportions.height / 2) < b ); // Top Half

        },
        intersectsWithEdge: function(item) {
            var y1 = this.position.absolute.top - 10, y2 = y1 + 10;
            var t = item.top,  b = t + item.height;

            if(!this.intersectsWith(item.item.parents(".ui-sortableTree").data("sortableTree").containerCache)) return false;

            if (!( t < y1 + (this.helperProportions.height / 2)        // Bottom Half
                &&     y2 - (this.helperProportions.height / 2) < b )) return false; // Top Half

            if(y2 > t && y1 < t) return 1; //Crosses top edge
            if(y1 < b && y2 > b) return 2; //Crosses bottom edge

            return false;

        },
        refresh: function() {
            this.refreshItems();
            this.refreshPositions();
        },
        refreshItems: function() {

            this.items = [];
            this.containers = [this];
            var items = this.items;
            var queries = [$(this.options.items, this.element)];

            if(this.options.connectWith) {
                for (var i = this.options.connectWith.length - 1; i >= 0; i--){
                    var cur = $(this.options.connectWith[i]);
                    for (var j = cur.length - 1; j >= 0; j--){
                        var inst = $.data(cur[j], 'sortableTree');
                        if(inst && !inst.options.disabled) {
                            queries.push($(inst.options.items, inst.element));
                            this.containers.push(inst);
                        }
                    };
                };
            }

            for (var i = queries.length - 1; i >= 0; i--){
                queries[i].each(function() {
                    $.data(this, 'sortableTree-item', true); // Data for target checking (mouse manager)
                    items.push({
                        item: $(this),
                        width: 0, height: 0,
                        left: 0, top: 0
                    });
                });
            };

        },
        refreshPositions: function(fast) {
            for (var i = this.items.length - 1; i >= 0; i--){
                if(!fast) this.items[i].height 			= this.items[i].item.outerHeight();
                this.items[i].top 						= this.items[i].item.offset().top;
            };
            for (var i = this.containers.length - 1; i >= 0; i--){
                var p =this.containers[i].element.offset();
                this.containers[i].containerCache.left 	= p.left;
                this.containers[i].containerCache.top 	= p.top;
                this.containers[i].containerCache.width	= this.containers[i].element.outerWidth();
                this.containers[i].containerCache.height= this.containers[i].element.outerHeight();
            };
        },
        destroy: function() {

            this.element
                .removeClass("ui-sortableTree ui-sortableTree-disabled")
                .removeData("sortableTree")
                .unbind(".sortableTree");
            this.mouseDestroy();

            for ( var i = this.items.length - 1; i >= 0; i-- )
                this.items[i].item.removeData("sortableTree-item");

        },
        contactContainers: function(e) {
            for (var i = this.containers.length - 1; i >= 0; i--){

                if(this.intersectsWith(this.containers[i].containerCache)) {
                    if(!this.containers[i].containerCache.over) {

                        if(this.currentContainer != this.containers[i]) {

                            //When entering a new container, we will find the item with the least distance and append our item near it
                            var dist = 10000; var itemWithLeastDistance = null; var base = this.position.absolute.top;
                            for (var j = this.items.length - 1; j >= 0; j--) {
                                if(!this.containers[i].element[0].contains(this.items[j].item[0])) continue;
                                var cur = this.items[j].top;
                                if(Math.abs(cur - base) < dist) {
                                    dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
                                }
                            }

                            itemWithLeastDistance ? this.rearrange(e, itemWithLeastDistance) : this.rearrange(e, null, this.containers[i].element);
                            this.propagate("change", e); //Call plugins and callbacks
                            this.containers[i].propagate("change", e, this); //Call plugins and callbacks
                            this.currentContainer = this.containers[i];

                        }

                        this.containers[i].propagate("over", e, this);
                        this.containers[i].containerCache.over = 1;
                    }
                } else {
                    if(this.containers[i].containerCache.over) {
                        this.containers[i].propagate("out", e, this);
                        this.containers[i].containerCache.over = 0;
                    }
                }

            };
        },
        mouseStart: function(e,el) {

            if(this.options.disabled || this.options.type == 'static') return false;

            //Find out if the clicked node (or one of its parents) is a actual item in this.items
            var currentItem = null, nodes = $(e.target).parents().each(function() {
                if($.data(this, 'sortableTree-item')) {
                    currentItem = $(this);
                    return false;
                }
            });
            if($.data(e.target, 'sortableTree-item')) currentItem = $(e.target);

            if(!currentItem) return false;
            if(this.options.handle) {
                var validHandle = false;
                $(this.options.handle, currentItem).each(function() { if(this == e.target) validHandle = true; });
                if(!validHandle) return false;
            }

            this.currentItem = currentItem;

            var o = this.options;
            this.currentContainer = this;
            this.refresh();

            //Create and append the visible helper
            this.helper = typeof o.helper == 'function' ? $(o.helper.apply(this.element[0], [e, this.currentItem])) : this.currentItem.clone();
            if(!this.helper.parents('body').length) this.helper.appendTo("body"); //Add the helper to the DOM if that didn't happen already
            this.helper.css({ position: 'absolute', clear: 'both' }).addClass('ui-sortableTree-helper'); //Position it absolutely and add a helper class

            //Prepare variables for position generation
            $.extend(this, {
                offsetParent: this.helper.offsetParent(),
                offsets: { absolute: this.currentItem.offset() }
            });

            //Save the first time position
            $.extend(this, {
                position: {
                    current: { left: e.pageX, top: e.pageY },
                    absolute: { left: e.pageX, top: e.pageY },
                    dom: this.currentItem.prev()[0]
                },
                clickOffset: { left: -5, top: -5 }
            });

            this.propagate("start", e); //Call plugins and callbacks
            this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; //Save and store the helper proportions

            for (var i = this.containers.length - 1; i >= 0; i--) {
                this.containers[i].propagate("activate", e, this);
            } //Post 'activate' events to possible containers

            //Prepare possible droppables
            if($.ui.ddmanager) $.ui.ddmanager.current = this;
            if ($.ui.ddmanager && !o.dropBehaviour) $.ui.ddmanager.prepareOffsets(this, e);

            this.dragging = true;
            return true;

        },
        mouseStop: function(e) {

            if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt); //remove sort indicator
            this.propagate("stop", e); //Call plugins and trigger callbacks

            //If we are using droppables, inform the manager about the drop
            var dropped = ($.ui.ddmanager && !this.options.dropBehaviour) ? $.ui.ddmanager.drop(this, e) : false;
            if(!dropped && this.newPositionAt) this.newPositionAt[this.direction == 'down' ? 'before' : 'after'](this.currentItem); //Append to element to its new position

            if(this.position.dom != this.currentItem.prev()[0]) this.propagate("update", e); //Trigger update callback if the DOM position has changed
            if(!this.element[0].contains(this.currentItem[0])) { //Node was moved out of the current element
                this.propagate("remove", e);
                for (var i = this.containers.length - 1; i >= 0; i--){
                    if(this.containers[i].element[0].contains(this.currentItem[0])) {
                        this.containers[i].propagate("update", e, this);
                        this.containers[i].propagate("receive", e, this);
                    }
                };
            };

            //Post events to containers
            for (var i = this.containers.length - 1; i >= 0; i--){
                this.containers[i].propagate("deactivate", e, this);
                if(this.containers[i].containerCache.over) {
                    this.containers[i].propagate("out", e, this);
                    this.containers[i].containerCache.over = 0;
                }
            }

            this.dragging = false;
            if(this.cancelHelperRemoval) return false;
            this.helper.remove();

            return false;

        },
        mouseDrag: function(e) {

            //Compute the helpers position
            this.position.current = { top: e.pageY + 5, left: e.pageX + 5 };
            this.position.absolute = { left: e.pageX + 5, top: e.pageY + 5 };

            //Interconnect with droppables
            if($.ui.ddmanager) $.ui.ddmanager.drag(this, e);
            var intersectsWithDroppable = false;
            $.each($.ui.ddmanager.droppables, function() {
                if(this.isover) intersectsWithDroppable = true;
            });

            //Rearrange
            if(intersectsWithDroppable) {
                if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt);
            } else {
                for (var i = this.items.length - 1; i >= 0; i--) {

                    if(this.currentItem[0].contains(this.items[i].item[0])) continue;

                    var intersection = this.intersectsWithEdge(this.items[i]);
                    if(!intersection) continue;

                    this.direction = intersection == 1 ? "down" : "up";
                    this.rearrange(e, this.items[i]);
                    this.propagate("change", e); //Call plugins and callbacks
                    break;
                }
            }

            //Post events to containers
            this.contactContainers(e);

            this.propagate("sort", e); //Call plugins and callbacks
            this.helper.css({ left: this.position.current.left+'px', top: this.position.current.top+'px' }); // Stick the helper to the cursor
            return false;

        },
        rearrange: function(e, i, a) {
            if(i) {
                if(this.newPositionAt) this.options.sortIndication.remove.call(this.currentItem, this.newPositionAt);
                this.newPositionAt = i.item;
                this.options.sortIndication[this.direction].call(this.currentItem, this.newPositionAt);
            } else {
                //Append
            }
        }
    }));

    $.extend($.ui.sortableTree, {
        defaults: {
            items: '> *',
            zIndex: 1000,
            distance: 1
        },
        getter: "serialize toArray"
    });



})(jQuery);

//edit
;(function($) {
    var CLASSES = $.treeview.classes;
    var proxied = $.fn.treeview;
    $.fn.treeview = function(settings) {
        settings = $.extend({}, settings);
        if (settings.add) {
            return this.trigger("add", [settings.add]);
        }
        if (settings.remove) {
            return this.trigger("remove", [settings.remove]);
        }
        return proxied.apply(this, arguments).bind("add", function(event, branches) {
            $(branches).prev()
                .removeClass(CLASSES.last)
                .removeClass(CLASSES.lastCollapsable)
                .removeClass(CLASSES.lastExpandable)
                .find(">.hitarea")
                .removeClass(CLASSES.lastCollapsableHitarea)
                .removeClass(CLASSES.lastExpandableHitarea);
            $(branches).find("li").andSelf().prepareBranches(settings).applyClasses(settings, $(this).data("toggler"));
        }).bind("remove", function(event, branches) {
            var prev = $(branches).prev();
            var parent = $(branches).parent();
            $(branches).remove();
            prev.filter(":last-child").addClass(CLASSES.last)
                .filter("." + CLASSES.expandable).replaceClass(CLASSES.last, CLASSES.lastExpandable).end()
                .find(">.hitarea").replaceClass(CLASSES.expandableHitarea, CLASSES.lastExpandableHitarea).end()
                .filter("." + CLASSES.collapsable).replaceClass(CLASSES.last, CLASSES.lastCollapsable).end()
                .find(">.hitarea").replaceClass(CLASSES.collapsableHitarea, CLASSES.lastCollapsableHitarea);
            if (parent.is(":not(:has(>))") && parent[0] != this) {
                parent.parent().removeClass(CLASSES.collapsable).removeClass(CLASSES.expandable)
                parent.siblings(".hitarea").andSelf().remove();
            }
        });
    };

})(jQuery);

//sync

